/*
 * Copyright (c) 2007 Marco Glietsch (http://www.mikrocontroller.net/topic/98697)
 * Original author: Marco Glietsch
 * Modified for octopus by Michael Hartmann <ich@speicherleck.de> (2011, 2012)
 * All rights reserved.
 *
 * Short descripton of file:
 *
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the following 
 *     disclaimer in the documentation and/or other materials provided 
 *     with the distribution.
 *   * Neither the name of the FH Augsburg nor the names of its 
 *     contributors may be used to endorse or promote products derived 
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF USE, 
 * DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef __AVR_AT90CAN128__

#include "can.h"
#include "common.h"
#include "protocol.h"

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>  
#include <inttypes.h>
#include <stdbool.h>


struct {
  uint32_t id;
  uint8_t data[8];
} message;

// extended id
int8_t extended_id;

void can_parser(uint8_t *buf)
{
  uint32_t idm = 0;
  uint32_t id  = 0;

  switch(buf[0])
  {
    case CMD_CAN_INIT:
      can_init_usb(buf[2], buf[3]);
      break;

    case CMD_CAN_DEINIT:
      can_deinit_usb();
      break;

    case CMD_CAN_ENABLE_MOB:
      id  = common_array2int(&buf[4]);
      idm = common_array2int(&buf[8]);

      // mob, mode, id, idm
      can_enable_mob_usb(buf[2], buf[3], id, idm);
      break;

    case CMD_CAN_DISABLE_MOB:
      can_disable_mob_usb(buf[2]);
      break;

    case CMD_CAN_SEND_DATA:
      id = common_array2int(&buf[3]);
                        // mob, id, length, data
      can_send_data_usb(buf[2], id, buf[7], &buf[8]);
      break;

    case CMD_CAN_SEND_REMOTE:
      can_send_remote_usb(buf[2]);
      break;

    case CMD_CAN_RECEIVE_DATA:
      can_receive_data_usb(0);
      break;

    case CMD_CAN_SET_AUTOREPLY:
      can_set_autoreply_usb(buf[2], buf[3], &buf[4]);
      break;

    case CMD_CAN_SILENT_MODE:
      can_silent_mode_usb(buf[2]);
      break;

    default:
      answer[0] = buf[0];
      answer[1] = RSP_UNKOWN_CMD;
      answer[2] = 0;
      CommandAnswer(3);
   }
}

void can_init_usb(uint8_t baudrate, uint8_t eid)
{
  answer[0] = CMD_CAN_INIT;
  answer[1] = (uint8_t)can_init(baudrate, CAN_INTERRUPT_RX, eid);
  answer[2] = 0;

  CommandAnswer(3);
}


void can_enable_mob_usb(uint8_t mob, uint8_t mode, uint32_t id, uint32_t idm)
{
  answer[0] = CMD_CAN_ENABLE_MOB;
  answer[1] = (int8_t)can_enable_mob(mob, mode, id, idm);
  answer[2] = 0;

  CommandAnswer(3);
}

void can_deinit_usb(void)
{
  answer[0] = CMD_CAN_DEINIT;
  answer[1] = (int8_t)can_deinit();
  answer[2] = 0;

  CommandAnswer(3);
}

void can_disable_mob_usb(uint8_t mob)
{
   answer[0] = CMD_CAN_DISABLE_MOB;
   answer[1] = (int8_t)can_disable_mob(mob);
   answer[2] = 0;

   CommandAnswer(3);
}

void can_send_remote_usb(uint8_t mob)
{
  answer[0] = CMD_CAN_SEND_REMOTE;
  answer[1] = (int8_t)can_send_remote(mob);
  answer[2] = 0;

  CommandAnswer(3);
}


void can_send_data_usb(uint8_t mob, uint32_t id, uint8_t length, uint8_t *data)
{
  answer[0] = CMD_CAN_SEND_DATA;
  answer[1] = (int8_t)can_send_data(mob, id, length, data);
  answer[2] = 0;

  CommandAnswer(3);
}

void can_receive_data_usb(int mob)
{
  answer[0] = CMD_CAN_RECEIVE_DATA;
  answer[1] = RSP_OK;
  answer[2] = message.id;
  answer[3] = message.id >> 8;
  answer[4] = message.id >> 16;
  answer[5] = message.id >> 24;

  answer[6]  = message.data[0];
  answer[7]  = message.data[1];
  answer[8]  = message.data[2];
  answer[9]  = message.data[3];
  answer[10] = message.data[4];
  answer[11] = message.data[5];
  answer[12] = message.data[6];
  answer[13] = message.data[7];

  answer[14] = 0;

  CommandAnswer(15);
}


void can_set_autoreply_usb(uint8_t mob, uint8_t length, uint8_t *buf)
{
  can_set_autoreply(mob, length, buf);

  answer[0] = CMD_CAN_SET_AUTOREPLY;
  answer[1] = RSP_OK;
  answer[2] = 0;

  CommandAnswer(3);
}

/* ------ CAN ------ */

// Message Objects zuruecksetzen, CAN-Controller aktivieren
// Parameter:
//   uint8_t baud: 0,1,2...5 (fuer 100, 125, 200, 250, 500, 1000)
//   uint8_t intmode: Ereignis, bei dem ein Interrupt ausgelöst werden soll
//     - NONE  - Deaktiviert
//     - TX    - Daten gesendet
//     - RX    - Daten empfangen
//     - TXRX  - Daten gesendet und/oder empfangen
int can_init(uint8_t baudrate, uint8_t intmode, uint8_t eid)
{
  uint8_t i;
  extended_id = eid ? 1 : 0;

  // Status- und Steuerregister aller Message Objects initialisieren
  for(i = 0; i < NO_MOBS; i++)
  {
    can_get_mob(i);
    CANSTMOB = 0;
    CANCDMOB = 0;
  }

  CANGCON |= (1 << SWRES);

  // set baudrate
  if(can_set_baudrate(baudrate) == 0)
    return 0;

  can_set_interrupt(intmode);

  // CAN-Controller in Enabled Mode setzen
  CANGCON = (1 << ENASTB);

  // Warten bis der CAN-Controller das Enabled-Bit gesetzt hat und
  // einsatzbereit ist
  while (!getbit(CANGSTA, ENFG));

  return 1; 
}

int can_deinit(void)
{
  uint8_t i;

  for(i = 0; i < 15; i++)
    can_disable_mob(i);

  // CAN-Controller ausschalten
  clearbit(CANGCON, ENASTB);

  // warten bis wirklich ausgeschaltet
  while (getbit(CANGSTA, ENFG));

  return 1;
}

void can_set_autoreply(uint8_t mob, uint8_t length, uint8_t *buf)
{
  can_get_mob(mob);
  can_set_mode(CAN_MODE_AUTO_REPLY);
  can_set_data(length, buf);
}

int can_set_baudrate(uint8_t baudrate)
{
    switch(baudrate)
    {
      case CAN_BAUDRATE_1000K:
        CANBT1 = 0x00; CANBT2 = 0x0c; CANBT3 = 0x37;
        break;

      case CAN_BAUDRATE_500K:
        CANBT1 = 0x02; CANBT2 = 0x0c; CANBT3 = 0x37;
        break;

      case CAN_BAUDRATE_250K:
        CANBT1 = 0x06; CANBT2 = 0x0c; CANBT3 = 0x37;
        break;

      case CAN_BAUDRATE_200K:
        CANBT1 = 0x08; CANBT2 = 0x0c; CANBT3 = 0x37;
        break;

      case CAN_BAUDRATE_125K:
        CANBT1 = 0x0e; CANBT2 = 0x0c; CANBT3 = 0x37;
        break;

      case CAN_BAUDRATE_100K:
        CANBT1 = 0x12; CANBT2= 0x0c;  CANBT3= 0x37;
        break;

      default:
        return 0;
    }

    return 1;
}

// Parameter:
//   uint8_t mob: Nummer des zu wählenden Objekts (0-14)
//
//   uint8_t mode
//     - Betriebsart des Message Objekts:
//     - DISABLED         Deaktiviert
//     - TRANSMIT_DATA    Daten senden
//     - TRANSMIT_REMOTE  Anfrage senden
//     - RECEIVE_DATA     Empfangsmodus
//     - AUTO_REPLY       automatischer Antwortmodus
//
int can_enable_mob(uint8_t mob, uint8_t mode, uint32_t id, uint32_t idm)
{
  // Objekt wählen
  can_get_mob(mob);

  // clear flags
  CANSTMOB = 0;

  // Betriebsmodus setzen
  if(can_set_mode(mode) == 0)
    return 0;

  // ID-Maske setzen
  can_set_id_mask(idm);

  // ID setzen
  can_set_id(id);

  // Interrupt für dieses Objekt aktivieren
  can_set_mob_interrupt(mob);

  return 1;
}


int can_send_data(uint8_t mob, uint32_t id, uint8_t length, uint8_t *data)
{
  uint8_t i;

  // load corresponding MOb page ...
  can_get_mob(mob);

  // clear flags
  CANSTMOB = 0;

  // DLC (Data Length Code)
  CANCDMOB = length;

  // set id
  can_set_id(id);

  for(i = 0; i < length; i++)
    CANMSG = data[i];

  // enable transmission
  CANCDMOB |= (1<<CONMOB0);

  return 1;
}


// Parameter: uint8_t mode: Ereignis, bei dem Interrupt ausgelöst werden soll
//   - NONE  - Deaktiviert
//   - TX    - Daten gesendet
//   - RX    - Daten empfangen
//   - TXRX  - Daten gesendet und/oder empfangen
int can_set_interrupt(uint8_t mode)
{
  uint8_t cangie = CANGIE;

  switch(mode)
  {
    case CAN_INTERRUPT_NONE:
      clearbit(cangie, ENIT);
      clearbit(cangie, ENRX);
      clearbit(cangie, ENTX);
      break;

    case CAN_INTERRUPT_TX:
      setbit  (cangie, ENIT);
      clearbit(cangie, ENRX);
      setbit  (cangie, ENTX);
      break;

    case CAN_INTERRUPT_RX:
      setbit  (cangie, ENIT);
      setbit  (cangie, ENRX);
      clearbit(cangie, ENTX);
      break;

    case CAN_INTERRUPT_TXRX:
      setbit(cangie, ENIT);
      setbit(cangie, ENRX);
      setbit(cangie, ENTX);
      break;

    default:
      return 0;
  }

  CANGIE = cangie;
  return 1;
}


// Funktion wählt CANPAGE des betreffenden Objekts aus und stellt Zugang zu
// Registern des Objekts her
void can_get_mob(uint8_t mob)
{
  CANPAGE = (mob << 4);
}

  
// Parameter: uint32_t idm: ID-Maske in Dezimalschreibweise
// Funktion setzt ID-Maske eines Objekts auf einen neuen Wert. In CANIDM4
// bleiben dabei die Werte der unteren 3 Bit (RTRTAG, Reserved und IDEMSK)
// erhalten.
void can_set_id_mask(uint32_t idm)
{
  //Standart identifier (11 bit)
  if(!(CANCDMOB & (1 << IDE)))
  {
    CANIDM2 = (uint8_t)(idm << 5); 
    CANIDM1 = (uint8_t)(idm >> 3);
  }
  //extended identifier
  else
  {
    idm <<= 3;
    idm  |= 7;

    CANIDM4 = (int8_t) (idm);
    CANIDM3 = (int8_t) (idm>>8);
    CANIDM2 = (int8_t) (idm>>16);
    CANIDM1 = (int8_t) (idm>>24);
  }
}

// Funktion holt ID der empfangenen Nachricht
uint32_t can_get_id(void)
{
  uint32_t id = 0;

  //Standart identifier (11 bit)
  if(!extended_id)
  {
    id  = (uint8_t)  CANIDT2 >> 5;
    id |= (uint16_t) CANIDT1 << 3;
  }
  //extended identifier
  else
  {
    id |= ((uint32_t) CANIDT1 << 24);
    id |= ((uint32_t) CANIDT2 << 16);
    id |= ((uint32_t) CANIDT3 << 8);
    id |= (CANIDT4&0xF8);
    id >>= 3;
  }

  return id;
}

// Funktion setzt ID eines Objekts auf einen neuen Wert. In CANIDM4 bleiben
// dabei die Werte der unteren 3 Bit (RTRTAG, RB1TAG und RB0TAG) erhalten.
void can_set_id(uint32_t id)
{
  if(extended_id)
  {
    // extended CAN ID
    CANCDMOB |= (1 << IDE);

    CANIDT4 = (uint8_t)  id << 3;

    uint32_t temp = id << 3;
    uint8_t *ptr = (uint8_t *) &temp;

    CANIDT3 = *(ptr + 1);
    CANIDT2 = *(ptr + 2);
    CANIDT1 = *(ptr + 3);
  }
  else {
    // standard CAN ID
    CANIDT4 = 0;
    CANIDT3 = 0;
    CANIDT2 = (uint8_t)  id << 5;
    CANIDT1 = (uint16_t) id >> 3;
  }
}

// Funktion setzt die Betriebsart des vorher gewählten Objekts.
// Parameter: uint8_t mode:
//   - Betriebsart des Message Objekts:
//   - DISABLED        - Deaktiviert
//   - TRANSMIT_DATA   - Daten senden
//   - TRANSMIT_REMOTE - Anfrage senden
//   - RECEIVE_DATA    - Empfangsmodus
//   - AUTO_REPLY      - automatischer Antwortmodus
int can_set_mode(uint8_t mode)
{
  uint8_t canidt4  = CANIDT4;
  uint8_t canidm4  = CANIDM4;
  uint8_t cancdmob = CANCDMOB;

  if(extended_id)
    setbit(cancdmob, IDE);
  else
    clearbit(cancdmob, IDE);

  switch(mode)
  {
    case CAN_MODE_DISABLED:
      clearbit(cancdmob, CONMOB0);
      clearbit(cancdmob, CONMOB1);
      clearbit(cancdmob, RPLV);
      clearbit(canidt4,  RTRTAG);
      clearbit(canidm4,  RTRMSK);
      break;

    case CAN_MODE_TRANSMIT_DATA:
      setbit  (cancdmob, CONMOB0);
      clearbit(cancdmob, CONMOB1);
      clearbit(cancdmob, RPLV);
      clearbit(canidt4,  RTRTAG);
      break;

    case CAN_MODE_TRANSMIT_REMOTE:
      clearbit(cancdmob, CONMOB1);
      setbit  (cancdmob, CONMOB0);
      clearbit(cancdmob, RPLV);
      setbit  (canidt4,  RTRTAG);
      break;

    case CAN_MODE_RECEIVE_DATA:
      clearbit(cancdmob, RPLV);
      clearbit(canidt4,  RTRTAG);
      CANCDMOB = cancdmob;
      CANIDT4  = canidt4;
      CANIDM4  = canidm4;
      setbit  (CANCDMOB, CONMOB1);
      return 1;
      break;

    case CAN_MODE_AUTO_REPLY:
      clearbit(cancdmob, CONMOB0);
      setbit  (cancdmob, CONMOB1);
      setbit  (cancdmob, RPLV);
      setbit  (canidt4, RTRTAG);
      break;

    default:
      return 0;
  }

  CANIDT4  = canidt4;
  CANIDM4  = canidm4;
  CANCDMOB = cancdmob;

  return 1;
}


// Funktion holt die Betriebsart des vorher gewaehlten Objekts
uint8_t can_get_mode(void)
{
  uint8_t mode = 0;

  if(!getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0))
    mode = CAN_MODE_DISABLED;
  else if(!getbit(CANCDMOB, CONMOB1) && getbit(CANCDMOB, CONMOB0) && !getbit(CANIDT4, RTRTAG))
    mode = CAN_MODE_TRANSMIT_DATA;
  else if(!getbit(CANCDMOB, CONMOB1) && getbit(CANCDMOB, CONMOB0) && getbit(CANIDT4, RTRTAG))
    mode = CAN_MODE_TRANSMIT_REMOTE;
  else if(getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0) && !getbit(CANIDT4, RTRTAG))
    mode = CAN_MODE_RECEIVE_DATA;
  else if(getbit(CANCDMOB, CONMOB1) && !getbit(CANCDMOB, CONMOB0) && getbit(CANCDMOB,RPLV) && getbit(CANIDT4, RTRTAG))
    mode = CAN_MODE_AUTO_REPLY;

  return mode;
}


// Funktion schreibt in das Objekt die zu uebermittelnden Daten
void can_set_data(uint8_t length, uint8_t *data)
{
  uint8_t i;

  if(length > 8)
    length = 8;

  // Anzahl der Datenbytes in der Nachricht
  // scheinbar darf man das CANCDMOB register nicht beliebig oft
  // schreiben/lesen, daher speichern wir den wert dazwischen, loeschen die
  // entsprechenden bits fuer die laenge und schreiben dann usere laenge rein
  // wie dem auch sei: so funktionierts zumindest, also vorsicht beim aufraeumen ;-)
  for(i = 0; i < length; i++)
    CANMSG = data[i];
}

void can_get_data(uint8_t *msg)
{
  uint8_t i;

  for(i = 0; i < 8; i++)
    msg[i] = CANMSG;
}

void can_silent_mode_usb(uint8_t mode)
{
  answer[0] = CMD_CAN_SILENT_MODE;
  answer[1] = can_silent_mode(mode);
  answer[2] = 0;
  CommandAnswer(3);
}

uint8_t can_silent_mode(uint8_t mode)
{
  uint8_t cangcon = CANGCON;

  if (mode) setbit(cangcon, LISTEN);
  else clearbit(cangcon, LISTEN);

  CANGCON = cangcon;
  return RSP_OK;
}

// Parameter: uint8_t mob: Nummer des Objekts (0-14)
// Funktion setzt den Interrupt für das jeweilige Objekt
void can_set_mob_interrupt(uint8_t mob)
{
  switch(mob)
  {
    case 0:  setbit(CANIE2, IEMOB0);  break;
    case 1:  setbit(CANIE2, IEMOB1);  break;
    case 2:  setbit(CANIE2, IEMOB2);  break;
    case 3:  setbit(CANIE2, IEMOB3);  break;
    case 4:  setbit(CANIE2, IEMOB4);  break;
    case 5:  setbit(CANIE2, IEMOB5);  break;
    case 6:  setbit(CANIE2, IEMOB6);  break;
    case 7:  setbit(CANIE2, IEMOB7);  break;

    case 8:  setbit(CANIE1, IEMOB8);  break;
    case 9:  setbit(CANIE1, IEMOB9);  break;
    case 10: setbit(CANIE1, IEMOB10); break;
    case 11: setbit(CANIE1, IEMOB11); break;
    case 12: setbit(CANIE1, IEMOB12); break;
    case 13: setbit(CANIE1, IEMOB13); break;
    case 14: setbit(CANIE1, IEMOB14); break;
  }
}

// Parameter: uint8_t mob: Nummer des Objekts (0-14)
// Funktion löscht den Interrupt für das jeweilige Objekt
void can_clear_mob_interrupt(uint8_t mob)
{
  switch(mob)
  {
    case 0:  clearbit(CANIE2, IEMOB0);  break;
    case 1:  clearbit(CANIE2, IEMOB1);  break;
    case 2:  clearbit(CANIE2, IEMOB2);  break;
    case 3:  clearbit(CANIE2, IEMOB3);  break;
    case 4:  clearbit(CANIE2, IEMOB4);  break;
    case 5:  clearbit(CANIE2, IEMOB5);  break;
    case 6:  clearbit(CANIE2, IEMOB6);  break;
    case 7:  clearbit(CANIE2, IEMOB7);  break;

    case 8:  clearbit(CANIE1, IEMOB8);  break;
    case 9:  clearbit(CANIE1, IEMOB9);  break;
    case 10: clearbit(CANIE1, IEMOB10); break;
    case 11: clearbit(CANIE1, IEMOB11); break;
    case 12: clearbit(CANIE1, IEMOB12); break;
    case 13: clearbit(CANIE1, IEMOB13); break;
    case 14: clearbit(CANIE1, IEMOB14); break;
  }
}

// Rückgabe: uint8_t mob: Nummer des Objekts
// Funktion ermittelt, welches Objekt Interrupt ausgeloest hat
uint8_t can_get_mob_interrupt(void)
{
  uint8_t  mob;
  uint16_t maske;
  maske = CANSIT2 | (CANSIT1 << 8);

  // Wenn alle 32 Bit der Bitmaske 0 sind dann ist ein Fehler aufgetreten
  if(maske == 0)
    return NOMOB;

  // Die Bitmaske wird so lange nach rechts geschoben, bis Bit0 eine 1 hat.
  // Die Anzahl der Schiebeoperatoren gibt somit die Nummer des MOBs zurück
  for(mob=0; (maske & 0x01)==0; maske >>= 1, ++mob);

  // Kontrolle: Wenn mob größer als die Anzahl der verfügbaren
  // Message Objects ist das Ergebnis falsch
  if(mob > 14)
    return NOMOB;

  return mob;
}


// Funktion deaktiviert das gewählte Objekt
int can_disable_mob(uint8_t mob)
{
  // Objekt wählen
  can_get_mob(mob);

  // Interrupt für dieses Objekt aktivieren
  can_clear_mob_interrupt(mob);

  // Betriebsmodus setzen
  can_set_mode(CAN_MODE_DISABLED);

  return 1;
}


// Funktion sendet eine Anfrage (Remote Frame)
int can_send_remote(uint8_t mob)
{
  uint8_t mode;

  // Objekt wählen
  can_get_mob(mob);
  
  // Aktuelle Betriebsart sichern
  mode = can_get_mode();

  // Datenübertragung starten
  can_set_mode(CAN_MODE_TRANSMIT_REMOTE);

  // Warten bis die Datenübertragung beendet ist (TXOK-Flag von CAN-Controller
  // gesetzt)
  while (!getbit(CANSTMOB, TXOK));      

  // TXOK-Flag von Hand löschen
  clearbit(CANSTMOB, TXOK);

  // Alte Betriebsart wiederherstellen
  can_set_mode(mode);

  return 1;
}


// Interrupt fuer Empfang einer Nachricht
ISR(CANIT_vect)
{
  uint8_t save_canpage;
  uint8_t mob;
  uint8_t canstmob;
/*
  DDRC  ^= 15;
  PORTC ^= 15;
*/

  // Aktuelle CANPAGE sichern
  save_canpage = CANPAGE;

  // Index des MOB ermitteln, der den Interrupt ausgelöst hat
  mob = can_get_mob_interrupt();
    
  // Falls es kein gültiges MOB war abbrechen
  if(mob == NOMOB)
    return;

  // Objekt das den Interrupt ausgelöst hat holen
  can_get_mob(mob);
  
  // Id der Nachricht holen und Daten des MOBs aus CANMSG auslesen
  message.id = can_get_id();
  can_get_data(message.data);

  canstmob = CANSTMOB;
  canstmob &= ~(1<<RXOK);
  CANSTMOB = canstmob;
  CANCDMOB |= (1<<CONMOB1);

  // CANPAGE wiederherstellen
  CANPAGE = save_canpage;
}


// interrupt service for CAN

/*
SIGNAL(SIG_CAN_INTERRUPT1)
{
  // CAN_messageType recMsg; this is a global variable
  uint8_t save_canpage = CANPAGE;   //  actual CANPAGE
  uint8_t mob;
  uint8_t i;
  uint8_t readmodwrite;

  // check in which MOb the INT was initiated
  mob = can_get_mob_interrupt();

  // select concerned MOb page
  CANPAGE = (mob << 4); 

  // Senden war erfolgreich
  if (CANSTMOB & (1<<TXOK))
  {
    readmodwrite = CANSTMOB;    
    readmodwrite &= ~(1<<TXOK); //  reset INT reason
  CANSTMOB = readmodwrite;      
  }
  // Nachricht erfolgreich empfangen
  else if (CANSTMOB & (1<<RXOK))
  {
    // hier kann etwas getan werden oder auch nicht
  // z.B. zum Test eine LED anschalten
  // ansonsten benutzt man die Nachricht aus recMsg dauerhaft in der main
  // und lässt sie durch den INT automatisch aktualisieren
DDRC ^= 15;
PORTC ^= 15;
    readmodwrite = CANSTMOB;
    readmodwrite &= ~(1<<RXOK);  //  reset interrupt  
    CANSTMOB = readmodwrite;
    CANCDMOB |= (1<<CONMOB1);  //  stay tuned!
  }



  CANPAGE = save_canpage;  //  restore CANPAGE

}
*/


#endif
